// DecisionMonitor.java
package org.zjx.core.monitor;

import org.zjx.core.DecisionNode;
import org.zjx.core.DecisionContext;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;

/**
 * 决策过程监控器（线程安全）
 *
 * 这个类用于监控决策引擎的执行情况，包括：
 * - 记录决策节点的执行时间和错误
 * - 跟踪决策执行路径（轨迹）
 * - 收集性能统计数据
 *
 * 设计特点：
 * - 线程安全：使用并发集合和原子变量
 * - 可配置的采样率：避免性能开销过大
 * - 可限制的追踪深度：防止内存溢出
 */
public class DecisionMonitor {
    // 配置参数
    private final double samplingRate;          // 采样率(0.01-1.0)，控制记录多少决策执行
    private final Set<String> monitoredNodes;   // 需要监控的节点ID集合
    private final int maxTraceDepth;            // 最大追踪深度，防止内存溢出

    // 数据存储
    private final Map<String, NodeStats> nodeStats = new ConcurrentHashMap<>();  // 节点统计信息
    private final Map<String, Deque<TraceRecord>> traces = new ConcurrentHashMap<>(); // 执行轨迹记录
    private final Map<String, AtomicLong> errorCounts = new ConcurrentHashMap<>();   // 错误计数

    /**
     * 构造函数
     * @param samplingRate 采样率(0.01-1.0)
     * @param monitoredNodes 需要监控的节点ID集合
     * @param maxTraceDepth 最大追踪深度
     */
    public DecisionMonitor(double samplingRate,
                           Set<String> monitoredNodes,
                           int maxTraceDepth) {
        // 确保采样率在合理范围内(0.01-1.0)
        this.samplingRate = Math.max(0.01, Math.min(1.0, samplingRate));
        // 防御性复制，避免外部修改
        this.monitoredNodes = new HashSet<>(monitoredNodes);
        // 确保最大深度不小于50
        this.maxTraceDepth = Math.max(50, maxTraceDepth);
    }

    /**
     * 记录节点执行耗时
     * @param node 决策节点
     * @param nanos 执行耗时(纳秒)
     */
    public void recordNodeExecution(DecisionNode node, long nanos) {
        // 只有被监控的节点且满足采样率才会记录
        if (shouldSample(node)) {
            String nodeId = node.getNodeId();
            // 使用computeIfAbsent原子性地获取或创建NodeStats
            nodeStats.computeIfAbsent(nodeId, k -> new NodeStats())
                    .recordExecution(nanos);
        }
    }

    /**
     * 记录执行轨迹
     * @param contextId 决策上下文ID
     * @param node 当前执行的节点
     * @param context 决策上下文
     */
    public void recordExecutionTrace(String contextId,
                                     DecisionNode node,
                                     DecisionContext context) {
        // 只有被监控的节点且满足采样率才会记录轨迹
        if (shouldSample(node)) {
            // 获取或创建该contextId对应的轨迹队列
            traces.computeIfAbsent(contextId, k -> new ConcurrentLinkedDeque<>())
                    .addLast(new TraceRecord(node.getNodeId(), System.currentTimeMillis(), context));

            // 控制追踪深度，防止内存溢出
            if (traces.get(contextId).size() > maxTraceDepth) {
                traces.get(contextId).removeFirst();
            }
        }
    }

    /**
     * 记录错误信息
     * @param node 发生错误的节点(可能为null)
     * @param error 错误对象
     */
    public void recordError(DecisionNode node, Throwable error) {
        // 获取错误类型名称
        String errorType = error.getClass().getSimpleName();
        // 原子性地增加该错误类型的计数
        errorCounts.computeIfAbsent(errorType, k -> new AtomicLong())
                .incrementAndGet();

        // 如果节点不为null，记录该节点的错误
        if (node != null) {
            nodeStats.computeIfAbsent(node.getNodeId(), k -> new NodeStats())
                    .recordError();
        }
    }

    /**
     * 判断是否应该采样记录当前节点
     * @param node 决策节点
     * @return 是否应该采样
     */
    private boolean shouldSample(DecisionNode node) {
        // 只有在监控列表中且满足采样率的节点才会被记录
        return monitoredNodes.contains(node.getNodeId()) &&
                ThreadLocalRandom.current().nextDouble() < samplingRate;
    }

    /**
     * 节点统计信息内部类
     * 使用LongAdder提高高并发下的计数性能
     */
    public static class NodeStats {
        private final LongAdder executionCount = new LongAdder();  // 执行次数
        private final LongAdder totalNanos = new LongAdder();      // 总耗时(纳秒)
        private final LongAdder errorCount = new LongAdder();      // 错误次数

        /**
         * 记录一次执行
         * @param nanos 执行耗时(纳秒)
         */
        public void recordExecution(long nanos) {
            executionCount.increment();
            totalNanos.add(nanos);
        }

        /**
         * 记录一次错误
         */
        public void recordError() {
            errorCount.increment();
        }

        /**
         * 计算平均执行时间(纳秒)
         * @return 平均执行时间(纳秒)
         */
        public double getAvgTimeNanos() {
            long count = executionCount.sum();
            return count > 0 ? totalNanos.sum() / (double) count : 0;
        }

        // Getters
        public long getExecutionCount() { return executionCount.sum(); }
        public long getTotalNanos() { return totalNanos.sum(); }
        public long getErrorCount() { return errorCount.sum(); }
    }

    /**
     * 轨迹记录内部类
     * 记录节点ID、时间戳和上下文信息
     */
    public static class TraceRecord {
        public final String nodeId;       // 节点ID
        public final long timestamp;      // 时间戳(毫秒)
        public final DecisionContext context; // 决策上下文

        public TraceRecord(String nodeId, long timestamp, DecisionContext context) {
            this.nodeId = nodeId;
            this.timestamp = timestamp;
            this.context = context;
        }
    }

    // Getters - 返回不可修改的视图以保证线程安全
    public Map<String, NodeStats> getNodeStats() { return Collections.unmodifiableMap(nodeStats); }
    public Map<String, Deque<TraceRecord>> getTraces() { return Collections.unmodifiableMap(traces); }
    public Map<String, AtomicLong> getErrorCounts() { return Collections.unmodifiableMap(errorCounts); }
}